/*
 *
 *      Copyright (c) 2018-2025, exsecs All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the pig4cloud.com developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: exsecs
 *
 */

package com.excesys.exsecs.admin.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.excesys.exsecs.admin.service.SysInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.text.DecimalFormat;
import com.sun.management.OperatingSystemMXBean;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.util.GlobalConfig;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 日志表 服务实现类
 * </p>
 *
 * @author exsecs
 * @since 2017-11-20
 */
@Service
@RequiredArgsConstructor
public class SysInfoServiceImpl implements SysInfoService {

	private final StringRedisTemplate redisTemplate;

	@Override
	public JSONObject systemInfo() throws Exception {
		JSONObject result = new JSONObject();
		SystemInfo systemInfo = new SystemInfo();
		// 1.获取CPU信息
		JSONObject cpuInfo = printlnCpuInfo(systemInfo);
		result.set("cpu", cpuInfo);
		// 2.获取内存信息
		JSONObject memoryInfo = printlnMemoryInfo(systemInfo);
		result.set("memory", memoryInfo);
		// 3. 获取磁盘信息
		JSONArray diskInfoList = printlnDiskInfo();
		result.set("disk", diskInfoList);
		// 4. 获取服务器信息
		JSONObject serverInfo = printlnServerInfo(systemInfo);
		result.set("server", serverInfo);
		// 5. 获取java信息
		JSONObject jvmInfo = printlnJvmInfo(systemInfo);
		result.set("jvm", jvmInfo);

		//获取mysql和redis的cpu占比
		JSONArray cpuArr = new JSONArray();
		String os = System.getProperty("os.name").toLowerCase();
		if (os.contains("win")) {
			//todo windows中mysql和redis的占比
			return result;
		} else{
			String[] command = new String[]{"ps -eo pcpu,comm --sort=-pcpu | grep mysqld | head -n 1", "ps -eo pcpu,comm --sort=-pcpu | grep redis-server | head -n 1"};
			for (String comm : command) {
				JSONObject json = getCpuProportion(comm);
				if (ObjectUtils.isNotEmpty(json)){
					cpuArr.add(json);
				}
			}
		}
		result.set("cpuProportion", cpuArr);
		return result;
	}

	private JSONObject getCpuProportion(String command ) {
		JSONObject json = new JSONObject();
		try{
			Process p = Runtime.getRuntime().exec(new String[]{"bash", "-c", command});
			BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
			String line;
			while ((line = br.readLine()) != null) {
				String[] parts = line.split("\\s+");
				if (parts.length > 1) {
					json.put("comm", parts[2]);
					json.put("cpu", parts[1]);
				}
				break;
			}
			br.close();
		}catch (Exception e){
			e.printStackTrace();
		}
		return json;
	}




	/**
	 * 打印 CPU 信息
	 * @param systemInfo
	 */
	private JSONObject printlnCpuInfo(SystemInfo systemInfo) throws InterruptedException {
		JSONObject cpuInfo = new JSONObject();
		GlobalConfig.set(GlobalConfig.OSHI_OS_WINDOWS_CPU_UTILITY, true);
		CentralProcessor processor = systemInfo.getHardware().getProcessor();
		long[] prevTicks = processor.getSystemCpuLoadTicks();
		TimeUnit.SECONDS.sleep(1);
		long[] ticks = processor.getSystemCpuLoadTicks();
		long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
		long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
		long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
		long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
		long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
		long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
		long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
		long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
		long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
		cpuInfo.put("cpuCore", processor.getLogicalProcessorCount());
		cpuInfo.put("cpuSysRate", new DecimalFormat("#.##%").format(cSys * 1.0 / totalCpu));//cpu系统使用率
		cpuInfo.put("cpuUserRate", new DecimalFormat("#.##%").format(user * 1.0 / totalCpu));//cpu用户使用率
		cpuInfo.put("cpuWaitRate", new DecimalFormat("#.##%").format(iowait * 1.0 / totalCpu));//cpu当前等待率
		cpuInfo.put("cpuFreeRate", new DecimalFormat("#.##%").format(idle * 1.0 / totalCpu));//cpu当前空闲率
		long cpuUtilization = user + nice + cSys  + iowait + irq + softirq + steal;
		cpuInfo.put("cpuUseRate", new DecimalFormat("#.##%").format(cpuUtilization * 1.0 / totalCpu));//cpu利用率
		return cpuInfo;
	}

	public JSONObject printlnMemoryInfo(SystemInfo systemInfo) {
		JSONObject memoryInfo = new JSONObject();
		OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
		// 总的物理内存
		String totalMemorySize = new DecimalFormat("#.##").format(osmxb.getTotalPhysicalMemorySize() / 1024.0 / 1024 / 1024);
		// 剩余的物理内存
		String freePhysicalMemorySize = new DecimalFormat("#.##").format(osmxb.getFreePhysicalMemorySize() / 1024.0 / 1024 / 1024);
		// 已使用的物理内存
		String usedMemory = new DecimalFormat("#.##").format((osmxb.getTotalPhysicalMemorySize() - osmxb.getFreePhysicalMemorySize()) / 1024.0 / 1024 / 1024);
		//JVM总内存
		String totalMemoryJvm = new DecimalFormat("#.##").format(systemInfo.getHardware().getMemory().getTotal() * 1.0 / 1024 / 1024 / 1024);
		String usedMemoryJvm = new DecimalFormat("#.##").format((systemInfo.getHardware().getMemory().getTotal() - systemInfo.getHardware().getMemory().getAvailable()) * 1.0 / 1024 / 1024 / 1024);
		String freeMemoryJvm = new DecimalFormat("#.##").format(systemInfo.getHardware().getMemory().getAvailable() * 1.0 / 1024 / 1024 / 1024);

		memoryInfo.put("totalMemory", totalMemorySize+ "G");
		memoryInfo.put("usedMemory", usedMemory  + "G");
		memoryInfo.put("freeMemory", freePhysicalMemorySize  + "G");
		memoryInfo.put("totalMemoryJvm",  totalMemoryJvm + "M");
		memoryInfo.put("usedMemoryJvm",  usedMemoryJvm + "M");
		memoryInfo.put("freeMemoryJvm",  freeMemoryJvm + "M");
		memoryInfo.put("totalMemoryRate", new DecimalFormat("#.##%").format(((osmxb.getTotalPhysicalMemorySize() - osmxb.getFreePhysicalMemorySize()) / 1024.0 / 1024 / 1024) / (osmxb.getTotalPhysicalMemorySize() / 1024.0 / 1024 / 1024)));
		double tmj =  systemInfo.getHardware().getMemory().getTotal() / 1024 / 1024 / 1024;
		double fmj =  (systemInfo.getHardware().getMemory().getTotal() - systemInfo.getHardware().getMemory().getAvailable()) / 1024 / 1024 / 1024;
		memoryInfo.put("usedMemoryJvmRate", new DecimalFormat("#.##%").format(fmj / tmj));
		return memoryInfo;
	}

	private JSONArray printlnDiskInfo() {
		JSONArray diskInfoList = new JSONArray();
		// 磁盘使用情况
		File[] files = File.listRoots();
		for (File file : files) {
			JSONObject item = new JSONObject();
			String total = new DecimalFormat("#.#").format(file.getTotalSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
			String free = new DecimalFormat("#.#").format(file.getFreeSpace() * 1.0 / 1024 / 1024 / 1024) + "G";
			String un = new DecimalFormat("#.#").format((file.getTotalSpace()- file.getFreeSpace()) * 1.0 / 1024 / 1024 / 1024) + "G";
			String unRate = new DecimalFormat("#.#").format(((file.getTotalSpace()- file.getFreeSpace())* 1.0 / 1024 / 1024 / 1024)/(file.getTotalSpace() * 1.0 / 1024 / 1024 / 1024) * 100) ;
			String path = file.getPath();
			item.put("path", path);//路径
			item.put("total", total);//总容量
			item.put("usedSpace", un);//已用空间
			item.put("freeSpace", free);//空闲空间
			item.put("usedRate", unRate);//已使用率
			diskInfoList.add(item);
		}
		return diskInfoList;
	}

	public JSONObject printlnServerInfo(SystemInfo systemInfo)throws Exception {
		JSONObject serverInfo = new JSONObject();
		// 操作系统
		InetAddress inetAddress = InetAddress.getLocalHost();
		String ipAddress = inetAddress.getHostAddress();
		Properties properties = System.getProperties();
		String osName = properties.getProperty("os.name");
		String isalist = properties.getProperty("sun.cpu.isalist");
		serverInfo.put("os", osName);
		serverInfo.put("architecture", isalist);//系统架构
		serverInfo.put("ip", ipAddress);
		return serverInfo;
	}

	public JSONObject printlnJvmInfo(SystemInfo systemInfo)throws Exception {
		JSONObject jvmInfo = new JSONObject();
		// jvm
		jvmInfo.put("startTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(ManagementFactory.getRuntimeMXBean().getStartTime())));//程序启动时间
		long millis = System.currentTimeMillis() - ManagementFactory.getRuntimeMXBean().getStartTime();
		long days = millis / (1000 * 60 * 60 * 24); // 计算天数
		long hours = (millis % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60); // 计算小时数
		long minutes = (millis % (1000 * 60 * 60)) / (1000 * 60); // 计算分钟数
		jvmInfo.put("days", days+"天"+hours+"时"+minutes+"分");
		jvmInfo.put("javaName", System.getProperty("java.vm.name"));
		jvmInfo.put("vmName", System.getProperty("vm.name"));
		jvmInfo.put("JavaVersion", System.getProperty("java.version"));
		jvmInfo.put("proPath" , System.getProperty("user.dir"));//项目路径
		jvmInfo.put("libraryPath" , System.getProperty("sun.boot.library.path"));//安装路径
		return jvmInfo;
	}


	/**
	 * 获取进程id
	 * @return
	 */
	public static String getPID() {
		String name = ManagementFactory.getRuntimeMXBean().getName();
		return name.split("@")[0];
	}
}
